package framework.service;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import framework.Message;
import framework.Trait;
import framework.server.Mail;
import framework.server.Server;
import framework.server.ServerException;

/**
 * MessageService.<br>
 * Extends AbstractService in order to extract messages from the queue.<br>
 *
 * @author Orlin Tomov
 * @version 0.2
 */
public abstract class MessageService extends AbstractService {

	private boolean available = true;

	/**
	 * @param	container
	 * @param	serviceName
	 */
	public MessageService(Trait container, String serviceName) {
		super(container, serviceName);
	}

	@Override
	protected Server getContainer() {
		return (Server) super.getContainer();
	}

	/**
	 * Returns the info of the service. 
	 *
	 * @return	service info
	 */
	@Override
	public String info() {
		String result = getServiceName() + "\n";
		if (available) {
			result += "available\n";
		} else {
			result += "busy\n";
		}
		return result;
	}

	/**
	 * Sends a message
	 * @param message
	 * @param sender
	 * @param reciever
	 */
	protected void sendMessage(Message message, String sender, String reciever) {
		getContainer().sendMessage(message, sender, reciever);
	}

	/**
	 * Main processing unit of the service
	 *
	 * @param	message
	 */
	protected void process(Message message) {
		Method method = null;
		try {
			method = getClass().getMethod("process", new Class[] {message.getClass()});
		} catch (SecurityException exception) {
			log.warn(exception);
		} catch (NoSuchMethodException exception) {
			oops(exception, message);
		}
		if (method != null) {
			try {
				method.invoke(this, new Object[] {message});
			} catch (IllegalArgumentException exception) {
				log.warn(exception);
			} catch (IllegalAccessException exception) {
				log.warn(exception);
			} catch (InvocationTargetException exception) {
				oops(exception.getTargetException(), message);
			}
		} else {
			/**/log.warn("unknown message " + message.getClass().getCanonicalName());
		}
	}

	protected void postProcess() {
	}

	protected void oops(Throwable exception, Message message) {
		log.error(message, exception);
	}

	/**
	 * Extracts a messages from the queue and process it
	 */
	@Override
	public void run() {
		try {
			init();
			while (getContainer().isRunning() && isRunning()) {
				if (isRunning()) {
					Mail mail = getContainer().pullMail(getServiceName());
					if (available && (mail == null)) {
						mail = getContainer().pullMail(getClass().getName());
					}
					if (mail == null) {
						try {
							sleep(100L);
						} catch(InterruptedException exception) {
							/**/log.error(exception.getMessage());
						}
					} else {
						process(mail.getMessage());
					}
					postProcess();
				} else { /** not running */
					try {
						sleep(100L);
					} catch(InterruptedException exception) {
						/**/log.error(exception.getMessage());
					}
				}
			}
		} catch (ServerException exception) {
			/**/log.error(exception.getMessage(), exception);
		}
	}

	protected void setAvailable(boolean available) {
		this.available = available;
	}
}
